package com.ytjj.qmyx.supplychain.api.filter;


import com.alibaba.fastjson.JSONObject;
import com.ytjj.qmyx.supplychain.api.config.IgnoreUrlsConfig;
import com.ytjj.qmyx.supplychain.common.api.ResultCode;
import com.ytjj.qmyx.supplychain.common.enums.ShopStatusEnum;
import com.ytjj.qmyx.supplychain.common.exception.ApiException;
import com.ytjj.qmyx.supplychain.common.utils.IPUtil;
import com.ytjj.qmyx.supplychain.mapper.entity.YxShopInfo;
import com.ytjj.qmyx.supplychain.service.ShopInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.map.LinkedMap;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;


/**
 * 签名认证拦截
 * 
 */
@Component
@Slf4j
public class AuthGlobalFilter implements Filter {
    @Resource
    private ShopInfoService shopInfoService;

    private static final String CONTENT_TYPE_JSON = "json";
    private final IgnoreUrlsConfig ignoreUrlsConfig;

    public AuthGlobalFilter(IgnoreUrlsConfig ignoreUrlsConfig) {
        this.ignoreUrlsConfig = ignoreUrlsConfig;
    }

    private static final String SECRET_KEY = "xxxxxx";

    public static void main(String[] args) {
        Map<String,String> map = new LinkedMap();
        map.put("contentType",CONTENT_TYPE_JSON);
        map.put("method","get");
        map.put("timestamp", "1629770158695");
        map.put("source","weapp");
        map.put("partentId", "ab2746ae6b084fe27b3275db41d72774");
        map.put("partentKey", "674d40749a2f44b8e400549167d70d93");
//        map.put("SECRET_KEY",SECRET_KEY);
        log.info(JSONObject.toJSONString(map));
        String sing = DigestUtils.md5Hex(JSONObject.toJSONString(map).toUpperCase());
        System.out.println(sing);
    }

    /**
     * 鉴权参数校验
     *
     * @param sourceSign
     * @param sign
     */
    private void authenticationSign(String sourceSign, String sign) {
        if (null == sign || !sign.equals(sourceSign)) {
            throw new ApiException(ResultCode.SIGN_FAILED);
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        if (ignoreUrlsConfig.getSwitchFlag().equals(0)) {
            filterChain.doFilter(servletRequest, servletResponse);
        }else {
            if (!(servletRequest instanceof HttpServletRequest) || !(servletResponse instanceof HttpServletResponse)) {
                throw new ServletException("拦截器仅支持HTTP请求");
            }
            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
            //ip验证
            authenticationIp(httpServletRequest);

            log.info(JSONObject.toJSONString(httpServletRequest.getRequestURI()));
            //白名单请求直接放行
            PathMatcher pathMatcher = new AntPathMatcher();
            boolean matchResult = false;
            for (String path : ignoreUrlsConfig.getUrls()) {
                if (pathMatcher.match("/**" + path, httpServletRequest.getServletPath())) {
                    matchResult = true;
                    break;
                }
            }
            log.info("===matchResult==={}", matchResult);
            if (matchResult) {
                filterChain.doFilter(servletRequest, servletResponse);
            } else {
                String sign = generateSign(httpServletRequest);
                String sourceSign = httpServletRequest.getHeader("sign");
                log.info("===sign={}, sourceSign={}", sign, sourceSign);
                authenticationSign(sourceSign, sign);
                filterChain.doFilter(servletRequest, servletResponse);
            }
        }
    }

    private void authenticationIp(HttpServletRequest httpServletRequest) {
        String addr = IPUtil.getIpAddress(httpServletRequest);
        log.info("===addr==={}", addr);
        if (!ignoreUrlsConfig.getIps().contains(addr)) {
            throw new ApiException(ResultCode.IP_FAILED);
        }
    }

    //生成sign签名
    private String generateSign(HttpServletRequest httpServletRequest) {
        String timestamp = httpServletRequest.getHeader("timestamp");
        String source = httpServletRequest.getHeader("source");
        String partentId = httpServletRequest.getHeader("partentId");
//        String partentKey = httpServletRequest.getHeader("partentKey");
        YxShopInfo shopInfo = shopInfoService.queryShopInfoByPartnerId(partentId);
        if (null == shopInfo) {
            throw new ApiException("非法商户信息");
        }
        if (!ShopStatusEnum.START.getCode().equals(shopInfo.getStatus())) {
            throw new ApiException("该商户已停用");
        }

        Map<String, String> map = new TreeMap<>();
        map.put("contentType", CONTENT_TYPE_JSON);
        map.put("timestamp", timestamp);
        map.put("source", source);
        map.put("partentId", partentId);
        map.put("partentKey", shopInfo.getParentKey());
        log.info(JSONObject.toJSONString(map));
        String sign = DigestUtils.md5Hex(JSONObject.toJSONString(map).toUpperCase());
        return sign;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ServletContext context = filterConfig.getServletContext();
        ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(context);
        shopInfoService = applicationContext.getBean("shopInfoService", ShopInfoService.class);
    }

    @Override
    public void destroy() {

    }
}
